require 'ziya'

class StatsController < ApplicationController
  include Ziya


  def average_crap
    @all_stats = Stat.all_stats
    render :nothing => true, :text => @all_stats.crap_avg.to_s
    return
  end
  
  # GET /stats
  # GET /stats.xml
  def index
    @tags = params[:tags]
    if @tags.nil? || @tags.length == 0     
      @all_stats = Stat.all_stats     
      @tags = ''
    else     
      @all_stats = Stat.all_stats_tagged_with_list(@tags)      
    end
    
    respond_to do |format|
      format.html # index.rhtml
      format.xml  { render :xml => @all_stats.to_xml }
      format.swf {
        graph  = Ziya::Charts::Scatter.new(nil, "All CRAP", 'scatter_index')
        if @tags.nil? || @tags.length == 0  
          list = Stat.find_crap_total.map {|result| [result.total_methods, result.crap] }      
        else      
          list = Stat.find_crap_total_for_tagged(@tags)
        end
        coords = []
        list.each {|s| 
          coords << s.total_methods
          coords << s.crap          
        }
        graph.add( :series, "CRAP", coords)
        graph.add( :axis_category_text,  ['x', 'y'] * (coords.size/2))
        graph.add(:theme, 'crap')
#        graph.add( :axis_value_text, "CRAP by TOTAL METHODS")
        render :xml => graph.to_xml        
      }
    end
  end
  
  def show_global_chart
    graph  = Ziya::Charts::Scatter.new(nil, "All CRAP", 'scatter_index')
    tags = params[:tags]
    list = []
    if tags.nil?
      list = Stat.find_crap_total.map {|result| [result.total_methods, result.crap] }      
    else      
      list = Stat.find_crap_total_for_tagged(tags)
    end
    coords = []
    list.each {|total_methods, crap| 
      coords << total_methods
      coords << crap          
    }
    graph.add( :series, "CRAP", coords)
    graph.add( :axis_category_text,  ['x', 'y'] * (coords.size/2))
    graph.add(:theme, 'crap')
#        graph.add( :axis_value_text, "CRAP by TOTAL METHODS")
    render :xml => graph.to_xml        
  end   

  def filter_global_chart
    @tags = params[:tags]
    
    if @tags.nil? || @tags.length == 0     
      @all_stats = Stat.all_stats     
      @tags = ''
    else     
      @all_stats = Stat.all_stats_tagged_with_list(@tags)      
    end

    render :layout => false
  end
  
  def show_global_comparative_chart
    @stat = Stat.find(params[:id])
    tags = params[:tags]
    list = []
    if tags.nil?
      #tags = @stat.tag_list.join(',')
      list = Stat.find_crap_total.map {|result| [result.total_methods, result.crap] }      
    else      
      list = Stat.find_crap_total_for_tagged(tags)
    end
    coords = []
    list.each {|total_methods, crap| 
      coords << total_methods
      coords << crap          
    }
    
    graph  = Ziya::Charts::Scatter.new(nil, "Comparative CRAP", 'scatter_show')
    graph.add( :series, "Other CRAP", coords)
    graph.add( :series, "Project CRAP", [@stat.total_methods, @stat.crap])
    graph.add( :axis_category_text,  ['x', 'y'] * (coords.size/2))
    graph.add(:theme, 'crap')
    render :xml => graph.to_xml        
  end
  
  
  def tag_cloud(tags, classes)

    return if tags.empty?
    
    max_count = tags.sort_by(&:count).last.count.to_f
    
    tags.each do |tag|
      index = ((tag.count / max_count) * (classes.size - 1)).round
      yield tag, classes[index]
    end

  end
    
  def show_detail
    @stat = Stat.find(params[:id])
    graph  = Ziya::Charts::StackedColumn.new(nil, nil, 'scatter_show')

    graph.add( :axis_category_text, [ "1", "2", "4", "8", "16", "32", "64", "128", "256"] )
    graph.add( :series, [@stat.ones, @stat.twos, @stat.fours, @stat.eights, @stat.sixteens, @stat.thirtytwos, @stat.sixtyfours, @stat.one28s, @stat.two56s] )
    graph.add(:theme, 'crap')
    render :xml => graph.to_xml        
  end
  
  # GET /individual_stats
  # GET /individual_stats.xml
  def individual_stats
    @tags = params[:tags]
    if @tags
      @stats = Stat.find_tagged_with(@tags)
    else
      @stats = Stat.find(:all)
    end
    render :partial => "stats", :locals => {:stats => @stats}
  end

  # GET /stats/1
  # GET /stats/1.xml
  def show    
    @stat = Stat.find(params[:id])    
    @add_badge = !flash[:notice].nil?    
    all_stats = Stat.all_stats
    @avgs, @diffs = compute_avgs_and_diffs(all_stats, @stat)
    
    respond_to do |format|
      format.html # show.rhtml
      format.xml  { render :xml => @stat.to_xml }
    end
  end

  
  def flip_comparison
    
    @stat = Stat.find(params[:stat])
    @tags = params[:tags]
    @flip = params[:flip]
    if @tags.nil?      
      all_stats = Stat.all_stats      
    else     
      all_stats = Stat.all_stats_tagged(@stat.tags)      
    end
    @avgs, @diffs = compute_avgs_and_diffs(all_stats, @stat)      
  end
  
  def show_detail
    @stat = Stat.find(params[:id])
#      respond_to do |format|
#      format.swf {
        graph  = Ziya::Charts::StackedColumn.new
        
        graph.add( :axis_category_text, [ "1", "2", "4", "8", "16", "32", "64", "128", "256"] )
        graph.add( :series, "Method CRAP Distribution", [@stat.ones, @stat.twos, @stat.fours, @stat.eights, @stat.sixteens, @stat.thirtytwos, @stat.sixtyfours, @stat.one28s, @stat.two56s] )
        graph.add(:theme, 'crap')
        render :xml => graph.to_xml        
#      }
  end

  def show_historical_crap_percent
    @stat = Stat.find(params[:id])
    @versions = @stat.versions.reverse
    if @versions.size == 0
      @versions << @stat
    end
    graph  = Ziya::Charts::Line.new        
    graph.add( :axis_category_text, @versions.map {|v| v.created_at.strftime('%m/%d/%y')}[0..9].reverse )
    graph.add( :series, "% CRAPpy Methods - Historical Trends", @versions.map {|v| v.crap}[0..9].reverse )
    graph.add(:theme, 'crap')
    render :xml => graph.to_xml        
  end
  
  def show_historical_crap_count
    @stat = Stat.find(params[:id])
    @versions = @stat.versions.reverse
    if @versions.size == 0
      @versions << @stat
    end
    graph  = Ziya::Charts::Line.new        
    graph.add( :axis_category_text, @versions.map {|v| v.created_at.strftime('%m/%d/%y')}[0..9].reverse )
    graph.add( :series, "CRAPload", @versions.map {|v| v.crap_load}[0..9].reverse)
    graph.add( :series, "Total Methods", @versions.map {|v| v.total_methods}[0..9].reverse )
    graph.add( :series, "CRAP Methods", @versions.map {|v| v.crap_methods}[0..9].reverse )
    graph.add(:theme, 'crap')
    render :xml => graph.to_xml        
  end

  def show_percent
    @stat = Stat.find(params[:id])
        graph  = Ziya::Charts::Bar.new(nil, "Percent CRAPpy Methods", "")
        graph.add( :axis_category_text, [""])
        graph.axis_ticks.category_ticks = :false
        crap_pct = [@stat.crap.to_f, 15].min
        graph.add( :series, "% CRAPpy Methods", [crap_pct] )
        graph.add(:theme, 'crap')
        
        graph.axis_value.min=0
        graph.axis_value.max=15
        graph.axis_value.steps=3
        render :xml => graph.to_xml         
  end

  
  # GET /stats/new
  def new
    stat = params[:stat]
    existing = nil
    project_hash = stat[:project_hash] if !stat.nil?
    existing = Stat.find_by_project_hash(project_hash) if !project_hash.nil?
    if !existing.nil?
      @tags = tags
      @stat = existing
      #@stat.crap = params[:stat][:crap]
      @stat.attributes=(params[:stat])
      @stat.created_at = Time.now
      render :action => :edit
    else
      @tags = tags
      @stat = Stat.new(params[:stat])
      @stat.created_at = Time.now
    end
  end
  
  # POST /stats
  # POST /stats.xml
  def create
    @tags = tags
    if params[:stat][:created_at].blank?
      params[:stat][:created_at] = Time.now
    end
    @stat = Stat.new(params[:stat])

    respond_to do |format|
      if @stat.save
#        puts "SAVED"
        flash[:notice] = 'Stat was successfully uploaded. Thank You for Sharing!'
        format.html { redirect_to stat_url(@stat) }
        format.xml  { head :created, :location => stat_url(@stat) }
      else
#        puts "NOT SAVED"
        format.html { render :action => "new" }
        format.xml  { render :xml => @stat.errors.to_xml }
      end
    end
  end

  
  
  # GET /stats/1;edit
  def edit
    @tags = tags
    # only allow edits from the new link, because we should only allow it for 
    # the report page upload link, not from the web.
    if @stat.nil?
      redirect_to :action => :index
    end
    
  end

  # PUT /stats/1
  # PUT /stats/1.xml
  def update
    @tags = tags
    @stat = Stat.find(params[:id])

    respond_to do |format|
      if @stat.update_attributes(params[:stat])
        flash[:notice] = 'Stat was successfully updated. Thank You for Sharing!'
        format.html { redirect_to stat_url(@stat) }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @stat.errors.to_xml }
      end
    end
  end

  # DELETE /stats/1
  # DELETE /stats/1.xml
  def destroy
    @stat = Stat.find(params[:id])
    @stat.destroy

    respond_to do |format|
      format.html { redirect_to stats_url }
      format.xml  { head :ok }
    end
  end
  
  def sd(difference, std_dev_size)
     if std_dev_size == 0 || difference == 0
	0
     else	
       (difference.abs / std_dev_size.to_f).ceil 
     end
  end  
  
  def select_global_tags
    sent_tags = params[:tags]
    @all_tags = tags
    if sent_tags.nil?
      @tags = @all_tags
    else
      @tags = sent_tags.split(", ")
    end
    render :layout => false
  end
  
  def tags
    Stat.tag_counts(:limit => 100, :order => 'count desc').sort {|x,y| x.name.downcase <=> y.name.downcase}
  end
  
  def compute_avgs_and_diffs(all_stats, stat)
    avgs = {}
    diffs = {}
    avgs['crap'] = all_stats.crap_avg.to_f
    diffs['crap'] = stat.crap.to_f - avgs['crap']
    #crap_sd = sd(crap_diff, all_stats.crap_std)
    
    avgs['crap_load'] = all_stats.crap_load_avg.to_f
    diffs['crap_load'] = stat.crap_load.to_i - avgs['crap_load']
    #crap_load_sd = sd(crap_load_diff, all_stats.crap_load_std)
    
    avgs['crap_methods'] = all_stats.crap_methods_avg.to_f
    diffs['crap_methods'] = stat.crap_methods.to_i - avgs['crap_methods']
    #crap_methods_sd = sd(crap_methods_diff, all_stats.crap_methods_std)
    
    avgs['total_methods'] = all_stats.total_methods_avg.to_f
    diffs['total_methods'] = stat.total_methods.to_i - avgs['total_methods']
    #total_methods_sd = sd(total_methods_diff, all_stats.total_methods_std)
    [avgs, diffs]
  end
end
